<script setup lang="ts">
import { Checkbox } from '@/models/reactiveComponent';
import { computed, ref, watch, inject, ComputedRef, Ref, reactive } from 'vue'
import * as injectKeys from "@/services/injectKeys";

const props = defineProps<{ model: Checkbox }>()
const model = props.model


const dbServices = inject(injectKeys.dbKey)!
const reactdataServices = inject(injectKeys.reactdataServicesKey)!
const appEventService = inject(injectKeys.appEventServiceKey)!;

appEventService.onResetFilters(() => {
    selecteds.clear()
});

const filterUtils = reactdataServices.getFilterUtils(model)


const data = filterUtils.getData()

let sqlPropName = null as unknown as string

const options = computed(() => {

    if (data.value.rows.length > 0) {
        const rows = data.value.rows

        if (!sqlPropName) {
            sqlPropName = data.value.fields[0]
        }

        return rows.map(r => {
            // null or undefined
            const noValue = r[sqlPropName] === undefined || r[sqlPropName] === null

            return {
                label: noValue ? '(空白)' : r[sqlPropName]!.toString(),
                value: noValue ? null : r[sqlPropName],
            }
        })
    }

    return []

})


const selecteds = reactive(new Set<string>())

watch(selecteds, setObj => {
    let values = Array.from(setObj.keys()) as (string | null)[]

    values = values.map(v => v === '(空白)' ? null : v)

    if (values.length === 0) {
        filterUtils.removeFilter()
    } else {
        const { hasNull, values: valuesWithoutNull } = dbServices.extractNullInValues(values)
        const sql = dbServices.valuesArray2sqlArray(valuesWithoutNull).join(',')

        filterUtils.addFilterWithExprFn(field => {
            const expr = `${field} in (${sql})`
            if (hasNull) {
                return `${expr} or ${field} is null`
            }

            return expr
        })

    }
})

let hiddenTitle = model.hiddenTitle ?? false



const checkRefs = computed(() => {
    const mapping = new Set<string>(
        selecteds.keys()
    )

    return options.value.map(v => {

        const checked = mapping.has(v.label) ? true : false
        return ref({ name: v.label, checked })
    })
})


function reverseLookupSelectedItemIndex(data: ComputedRef<Ref<{
    name: string;
    checked: boolean;
}>[]>, startIndex: number) {
    for (let index = startIndex; index >= 0; index--) {
        const element = data.value[index].value;

        if (element.checked) {
            return index
        }
    }

    return 0
}

function onCheckStateChanged(e: Event, label: string, refsIndex: number) {

    const event = e as PointerEvent

    if (model.multiple && event.shiftKey) {
        const startIndex = reverseLookupSelectedItemIndex(checkRefs, refsIndex)

        checkRefs.value.slice(startIndex, refsIndex + 1).forEach(v => {
            if (!v.value.checked && !selecteds.has(v.value.name)) {
                selecteds.add(v.value.name)
            }
        })

        return
    }

    const checked = !checkRefs.value[refsIndex].value.checked

    if (checked && !selecteds.has(label)) {
        // 单选需要取消其他的选项
        if (!model.multiple) {
            selecteds.clear()
        }

        selecteds.add(label)
    }

    if (!checked && selecteds.has(label)) {
        selecteds.delete(label)
    }


}


function onReset() {
    selecteds.clear()
}

function onAllSelected() {

    checkRefs.value.forEach(v => {
        if (!selecteds.has(v.value.name)) {
            selecteds.add(v.value.name)
        }
    })
}

function onDeSelected() {

    checkRefs.value.forEach(v => {
        if (v.value.checked && selecteds.has(v.value.name)) {
            selecteds.delete(v.value.name)
        }

        if (!v.value.checked && !selecteds.has(v.value.name)) {
            selecteds.add(v.value.name)
        }
    })
}

const itemDirection = model.itemDirection
</script>

<template>
    <div class="pybi-checkbox">
        <header>
            <span class="title">{{ model.title }}</span>


            <div class="funs-buttons">
                <span class="all-selected funs-icon" v-if="model.multiple" v-tooltip="{ content: '全选', position: 'left' }"
                    @click="onAllSelected">
                    <svg viewBox="0 0 1024 1024">
                        <path
                            d="M511.1 957.94c-246.456 0-446.857-200.401-446.857-446.859S264.644 64.223 511.1 64.223c246.457 0 446.858 200.401 446.858 446.858S757.557 957.94 511.1 957.94z m0-851.396c-222.806 0-404.537 181.73-404.537 404.537S288.295 915.619 511.1 915.619c222.807 0 404.537-181.73 404.537-404.537S734.53 106.544 511.1 106.544z m167.417 262.017L447.619 601.325 343.685 496.767c-9.335-9.335-24.895-9.335-34.853 0-9.335 9.335-9.335 24.895 0 34.853l121.984 121.983c9.336 9.336 24.895 9.336 34.853 0 1.244-1.244 1.866-2.489 3.112-3.733l245.211-246.457c9.336-9.335 9.336-24.895 0-34.852-9.959-9.959-25.518-9.959-35.475 0z">
                        </path>
                    </svg>
                </span>

                <span class="de-selected funs-icon" v-if="model.multiple" @click="onDeSelected"
                    v-tooltip="{ content: '反选', position: 'left' }">
                    <svg viewBox="0 0 1024 1024">
                        <path
                            d="M832 448a64 64 0 0 1 64 64v320a64 64 0 0 1-64 64H512a64 64 0 0 1-64-64V512a64 64 0 0 1 64-64h320z m-576.448 218.496L256 672V832h96a32 32 0 0 1 31.488 26.24L384 864a32 32 0 0 1-26.24 31.488L352 896h-128a32 32 0 0 1-31.488-26.24L192 864v-114.816l-41.344 41.472a32 32 0 0 1-40.832 3.648l-4.48-3.648a32 32 0 0 1-3.648-40.832l3.648-4.48 96-96a32 32 0 0 1 54.208 17.152zM832 512H512v320h320V512z m-9.344 73.344a32 32 0 0 1 3.648 40.832l-3.648 4.48-128 128a32 32 0 0 1-35.456 6.656l-4.928-2.688-96-64a32 32 0 0 1 30.4-56l5.12 2.752 74.112 49.408 109.44-109.44a32 32 0 0 1 45.312 0zM512 128a64 64 0 0 1 64 64v192H512V192H192v320h192v64H192a64 64 0 0 1-64-64V192a64 64 0 0 1 64-64h320z m288-0.064a32 32 0 0 1 31.488 26.24L832 160v114.816l41.344-41.472a32 32 0 0 1 40.832-3.648l4.48 3.648a32 32 0 0 1 3.648 40.832l-3.648 4.48-96 96a32 32 0 0 1-54.208-17.152L768 351.936v-160h-96a32 32 0 0 1-31.488-26.24L640 159.936a32 32 0 0 1 26.24-31.488L672 128h128z">
                        </path>
                    </svg>
                </span>

                <span class="reset-filter funs-icon" @click="onReset" v-tooltip="{ content: '重置', position: 'left' }">
                    <svg viewBox="0 0 1024 1024">
                        <path
                            d="M214.864 440.317l69.471-41.742c20.83-12.516 47.862-5.776 60.377 15.053 12.516 20.83 5.776 47.862-15.053 60.377L137.653 589.374 22.285 397.369c-12.516-20.83-5.776-47.862 15.053-60.378 20.83-12.515 47.862-5.775 60.377 15.054l34.478 57.38c36.81-123.472 126.622-227 249.697-279.243 223.634-94.927 481.893 9.459 576.842 233.144 94.948 223.685-9.365 481.973-232.998 576.9-161.485 68.546-346.059 34.258-472.152-83.359-17.77-16.575-18.738-44.418-2.162-62.188 16.575-17.77 44.418-18.738 62.187-2.163 100.9 94.117 248.546 121.546 377.742 66.705C870.24 783.287 953.688 576.663 877.727 397.71c-75.96-178.953-282.562-262.459-461.452-186.524-100.372 42.605-173.066 127.8-201.411 229.131z"
                            fill="#000000"></path>
                    </svg>
                </span>

            </div>

        </header>

        <div class="list-mode" v-if="model.mode === 'list'">
            <div class="labels-box">

                <div v-for="(item, idx) in options" :key="item.label" class="pybi-checkbox_content">

                    <input type="checkbox" :checked="checkRefs[idx].value.checked"
                        @change="e => onCheckStateChanged(e, item.label, idx)">
                    <span>{{ item.label }}</span>

                </div>

            </div>
        </div>

        <div class="tile-mode" v-if="model.mode === 'tile'">
            <div class="labels-box">


                <div v-for="(item, idx) in options" :key="item.label" class="pybi-checkbox_content "
                    :class="{ 'pybi-checkbox_content-checked': selecteds.has(item.label) }"
                    @click="e => onCheckStateChanged(e, item.label, idx)">

                    <span>{{ item.label }}</span>

                </div>

            </div>
        </div>


    </div>
</template>

<style scoped lang="less">
.pybi-checkbox {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;

    width: 100%;
    position: relative;

    & svg {
        width: 1em;
        height: 1em;
    }


    >header {
        background-color: rgb(173, 207, 243);
        border-radius: 5px;
        height: 25px;
        width: 100%;
        flex-shrink: 0;
        display: flex;
        justify-content: space-between;
        align-items: center;

        .title {
            font-size: 1.1em;
            padding: 0.1em 0.3em;
        }


        .funs-buttons {
            display: flex;
            flex-direction: row;

            .funs-icon {
                border-radius: 50%;
                display: flex;
                justify-content: center;
                align-items: center;
                padding: 0.3em;

                user-select: none;
                transition: 0.3s;
                cursor: pointer;

                &:hover {
                    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                }
            }


        }

    }



    .list-mode {
        overflow: auto;

        .labels-box {
            display: flex;
            flex-wrap: nowrap;
            flex-direction: column;
            gap: 0.5em;

            .pybi-checkbox_content {
                display: flex;
                gap: 0.3em;
                justify-content: flex-start;
                align-items: center;

                user-select: none;

                height: 1.5em;
            }

        }

    }

    .tile-mode {
        // --color-opactiy: 0.9;
        --label-main-color: rgba(203, 222, 242, 0.9);

        overflow: auto;

        .labels-box {
            display: flex;
            flex-wrap: wrap;
            flex-direction: v-bind(itemDirection);
            gap: 0.2em;
            padding: 0.3em 0.1em;
            padding-left: 0;



            .pybi-checkbox_content {
                border: 1px solid var(--label-main-color);
                border-radius: 15px;
                // width: 8em;
                height: 3em;

                padding: 1em;
                display: flex;
                gap: 0.3em;
                justify-content: center;
                align-items: center;

                user-select: none;
                cursor: pointer;

                height: 1.5em;
                transition: 0.3s;

                &:hover {
                    text-decoration: underline;
                }
            }

            .pybi-checkbox_content-checked {
                background-color: var(--label-main-color);

            }

        }

    }

}

// .pybi-checkbox_content,
// .pybi-checkbox_content-checked {
//     background-color: rgb(38, 38, 38);
//     color: aliceblue;
// }
</style>